package com.workplan.client.widgets.workdays;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;

import com.general.client.basewidget.BaseWidget;
import com.general.client.callback.Callback;
import com.general.client.position.Position;
import com.general.client.widgets.checkbox.Checkbox;
import com.general.client.widgets.combobox.Combobox;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Widget;
import com.workplan.shared.datamodel.workweek.Workweek.WorkDays;

public class Workdays extends BaseWidget implements WorkdaysPresenter.Display {

	@UiField
	Label label;

	@UiField
	Checkbox sunday;
	@UiField
	Checkbox monday;
	@UiField
	Checkbox tuesday;
	@UiField
	Checkbox wednesday;
	@UiField
	Checkbox thursday;
	@UiField
	Checkbox friday;
	@UiField
	Checkbox saturday;

	@UiField
	Combobox<WorkDays> startDayCombo;

	private final ArrayList<Callback<Set<WorkDays>>> onSelectedDaysChangedCallbackList = new ArrayList<Callback<Set<WorkDays>>>();
	private final HashMap<Checkbox, WorkDays> checkboxToValueMapper = new HashMap<Checkbox, WorkDays>();
	private final HashMap<WorkDays, Checkbox> valueToCheckboxMapper = new HashMap<WorkDays, Checkbox>();
	private final HashSet<WorkDays> selectedWorkdays = new HashSet<WorkDays>();

	private static DefineWorkweekUiBinder uiBinder = GWT
			.create(DefineWorkweekUiBinder.class);

	interface DefineWorkweekUiBinder extends UiBinder<Widget, Workdays> {
	}

	public Workdays() {
		initWidget(uiBinder.createAndBindUi(this));
		label.setText("Workdays");
		init();
	}

	private void init() {
		initWorkday(sunday, WorkDays.SUNDAY, "Sun.");
		initWorkday(monday, WorkDays.MONDAY, "Mon.");
		initWorkday(tuesday, WorkDays.TUESDAY, "Tue.");
		initWorkday(wednesday, WorkDays.WEDNESDAY, "Wed.");
		initWorkday(thursday, WorkDays.THURSDAY, "Thu.");
		initWorkday(friday, WorkDays.FRIDAY, "Fri.");
		initWorkday(saturday, WorkDays.SATURDAY, "Sat.");

		initStartDayCombo();
	}

	private void initStartDayCombo() {
		for (WorkDays wd : WorkDays.values()) {
			startDayCombo.addItem(wd, wd.name());
		}
		startDayCombo.setValue(WorkDays.MONDAY);
		startDayCombo.setLabel("Week starts on:");
		startDayCombo.setLabelPosition(Position.ABOVE);
	}

	private void initWorkday(final Checkbox dayCheckbox, WorkDays value,
			String label) {

		dayCheckbox.setLabel(label);
		dayCheckbox.setLabelPosition(Position.ABOVE);
		dayCheckbox.setValue(false);
		checkboxToValueMapper.put(dayCheckbox, value);
		valueToCheckboxMapper.put(value, dayCheckbox);
		dayCheckbox.addValueChangeHandler(new ValueChangeHandler<Boolean>() {

			@Override
			public void onValueChange(ValueChangeEvent<Boolean> event) {
				if (event.getValue()) {
					selectedWorkdays.add(checkboxToValueMapper.get(dayCheckbox));
				} else {
					selectedWorkdays.remove(checkboxToValueMapper
							.get(dayCheckbox));
				}

				invokeSelectedDaysChangedCallbacks(
						onSelectedDaysChangedCallbackList,
						getSelectedWorkdays());
			}
		});

	}

	private void invokeSelectedDaysChangedCallbacks(
			ArrayList<Callback<Set<WorkDays>>> onSelectedDaysChangedCallbackList,
			Set<WorkDays> selectedWorkdays) {
		for (Callback<Set<WorkDays>> cb : onSelectedDaysChangedCallbackList) {
			cb.onItemChanged(selectedWorkdays);
		}
	}

	@Override
	public Set<WorkDays> getSelectedWorkdays() {
		return selectedWorkdays;
	}

	@Override
	public void setSelectedWorkdays(Set<WorkDays> selected) {
		for (WorkDays wd : WorkDays.values()) {
			boolean selectedDay = selected.contains(wd);
			valueToCheckboxMapper.get(wd).setValue(selectedDay);
		}
		selectedWorkdays.clear();
		selectedWorkdays.addAll(selected);
	}

	@Override
	public void onSelectedDaysChanged(Callback<Set<WorkDays>> callback) {
		this.onSelectedDaysChangedCallbackList.add(callback);
	}

	@Override
	public WorkDays getWeekStartDay() {
		return startDayCombo.getValue();
	}

	@Override
	public void setWeekStartDay(WorkDays workDays) {
		startDayCombo.setValue(workDays);
	}

	@Override
	public void onWeekStartDayChanged(Callback<WorkDays> callback) {
		startDayCombo.onSelectedItemChanged(callback);
	}

}
